package com.xiashitech.agent.instrumentation.redis;

import com.xiashitech.agent.config.StartConfig;
import com.xiashitech.agent.constants.Instrumentation;
import com.xiashitech.agent.dto.UserRequest;
import com.xiashitech.agent.instrumentation.base.AbstractAttributesExtractor;
import com.xiashitech.agent.instrumentation.base.context.TraceContextVars;
import com.xiashitech.agent.instrumentation.bridge.Java8Bridge;
import com.xiashitech.agent.instrumentation.utils.BaggageUtil;
import com.xiashitech.agent.instrumentation.utils.MachineAttributesUtil;
import com.xiashitech.agent.utils.JsonUtil;
import com.xiashitech.agent.utils.UserMatchUtil;
import com.xiashitech.interfaces.agent.dto.SystemInfoDTO;
import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
import io.opentelemetry.javaagent.shaded.io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.javaagent.shaded.io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.javaagent.shaded.io.opentelemetry.api.trace.Span;
import io.opentelemetry.javaagent.shaded.io.opentelemetry.context.Context;
import org.jetbrains.annotations.Nullable;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.util.Optional;

public class XSJedisAttributesExtractor extends AbstractAttributesExtractor<RedisData,RedisData> {
    public String getAttributesExtractorName() {
        return XSJedisAttributesExtractor.class.getName();
    }
    @Override
    public void onXSStart(AttributesBuilder attributesBuilder, Context context, RedisData redisData) {
        Baggage baggage = Baggage.fromContext(context);
        System.out.println("###jedis traceid "+ Span.current().getSpanContext().getTraceId());
        System.out.println("###jedis time "+ System.currentTimeMillis()+"redis data "+redisData.toString());

        if(redisData == null) {
            return;
        }
        try {
            //如下if else 语句后续会合并，考虑不同方法可能会有不同逻辑暂时保留，通过项目积累验证
            if(redisData.getRedisOpetion().equals(Instrumentation.Redis_Opetion_Hset)) {
                if(redisData != null && redisData.getKey() != null && redisData.getValue() != null) {
//                String tokenKey = new String(redisData.getKey());
//                //检查token有效性，初步判断为登陆操作，在UserInfoMatchRule.executeRule会获取用户标识，获取不到表明不是登陆操作
//                if(UserMatchUtil.judgeTokenValid(tokenKey)) {
                    setAttributesForLogin(attributesBuilder,redisData,context);
//                }
                }
            } else if(redisData.getRedisOpetion().equals(Instrumentation.Redis_Opetion_PAndSetEx) || redisData.getRedisOpetion().equals(Instrumentation.Redis_Opetion_SetEX) || redisData.getRedisOpetion().equals(Instrumentation.Redis_Opetion_PSetEX) || redisData.getRedisOpetion().equals(Instrumentation.Redis_Opetion_Set)) {
                if(redisData != null && redisData.getKey() != null && redisData.getValue() != null) {
                    String tokenKey = new String(redisData.getKey());
                    //检查token有效性，初步判断为登陆操作，在UserInfoMatchRule.executeRule会获取用户标识，获取不到表明不是登陆操作
                    if(UserMatchUtil.judgeTokenValid(tokenKey)) {
                        setAttributesForLogin(attributesBuilder,redisData,context);
                    }
                }
            }
        } catch (Throwable e) {
            StartConfig.throwableStackPrinter(e);
        }
    }

    @Override
    public void onXSEnd(AttributesBuilder attributesBuilder, Context context, RedisData redisDataRequest, @Nullable RedisData redisDataResponse, @Nullable Throwable throwable) {
        //Baggage baggage = BaggageUtil.mergeBaggageFromContext(Baggage.current(), context).build();
        if(redisDataRequest == null || redisDataResponse == null) {
            return;
        }
        if(InstrumentationConfig.get().getBoolean("xs.debug.redis",false)) {
            try {
                attributesBuilder.put("xs.rediskey", new String(redisDataRequest.getKey()));
                attributesBuilder.put("xs.redisfield", new String(redisDataRequest.getField()));
                String jsonObj = new String(redisDataRequest.getValue());
                if (JsonUtil.isJson(jsonObj)) {
                    attributesBuilder.put("xs.redisvalue", jsonObj);
                } else {
                    try (
                            ByteArrayInputStream bis = new ByteArrayInputStream(redisDataRequest.getValue());
                            ObjectInputStream ois = new ObjectInputStream(bis);
                    ) {
                        attributesBuilder.put("xs.redisvalue", JsonUtil.convertObjectToString(ois.readObject()));
                    } catch (Throwable e) {
                        attributesBuilder.put("xs.redisvalue", jsonObj);
                    }
                }
            } catch (Throwable e) {
            }
        }
        try {
            //如下if else 语句后续会合并，考虑不同方法可能会有不同逻辑暂时保留，通过项目积累验证
            if(redisDataRequest.getRedisOpetion().equals(Instrumentation.Redis_Opetion_Hget)) {
                String logintoken = BaggageUtil.getTraceVar(context, "xs.logintoken");
                if(logintoken == null && redisDataResponse.getRedissonRequest() != null && redisDataResponse.getRedissonRequest().getBaggage() != null) {
                    logintoken = redisDataResponse.getRedissonRequest().getBaggage().getEntryValue("xs.logintoken");
                }
                if(redisDataResponse.getKey() == null) {
                    return;
                }
                String key = new String(redisDataResponse.getKey());
                if(logintoken != null && !logintoken.isEmpty() && key.contains(logintoken)) {
                    Optional<UserRequest> redisDataOptional = Java8Bridge.executeRuleForUserInfoMatchRule(redisDataResponse);
                    if(redisDataOptional.isPresent()) {
                        UserRequest userRequest = redisDataOptional.get();
                        setAttributes(attributesBuilder,userRequest,context,false);
                    }
                }
            } else if (redisDataRequest.getRedisOpetion().equals(Instrumentation.Redis_Opetion_HgetAll)) {


            } else if (redisDataRequest.getRedisOpetion().equals(Instrumentation.Redis_Opetion_Get)) {
                String logintoken = BaggageUtil.getTraceVar(context, "xs.logintoken");
                if(logintoken == null && redisDataResponse.getRedissonRequest() != null && redisDataResponse.getRedissonRequest().getBaggage() != null) {
                    logintoken = redisDataResponse.getRedissonRequest().getBaggage().getEntryValue("xs.logintoken");
                }
                if(redisDataResponse.getKey() == null) {
                    return;
                }
                String key = new String(redisDataResponse.getKey());
                if(logintoken != null && !logintoken.isEmpty() && key.contains(logintoken)) {
                    Optional<UserRequest> redisDataOptional = Java8Bridge.executeRuleForUserInfoMatchRule(redisDataResponse);
                    if(redisDataOptional.isPresent()) {
                        UserRequest userRequest = redisDataOptional.get();
                        setAttributes(attributesBuilder,userRequest,context,false);
                    }
                }
            }
            MachineAttributesUtil.fillMachineAttributes(attributesBuilder);
        } catch (Throwable e) {
            StartConfig.throwableStackPrinter(e);
        }
    }

    /**
     * 登陆
     * @param attributesBuilder
     * @param redisData
     */
    private void setAttributesForLogin(AttributesBuilder attributesBuilder, RedisData redisData, Context context) {
        Optional<UserRequest> redisDataOptional = Java8Bridge.executeRuleForUserInfoMatchRule(redisData);
        if(redisDataOptional.isPresent() && redisDataOptional.get().getSessionId() != null && !"".equals(redisDataOptional.get().getSessionId()) && redisDataOptional.get().getUserid() != null && !"".equals(redisDataOptional.get().getUserid())) {
            setAttributes(attributesBuilder,redisDataOptional.get(),context,true);
        }
    }

    private void setAttributes(AttributesBuilder attributes,UserRequest userRequest, Context context,Boolean sessionUpdate) {
        try {
            attributes.put("xs.userId",userRequest.getUserid() == null ? "" : userRequest.getUserid());
            attributes.put("xs.sessionId",userRequest.getSessionId() == null ? "" : userRequest.getSessionId());
            attributes.put("xs.requestDate",userRequest.getRequestDate() == null ? "" : userRequest.getRequestDate().toString());
            attributes.put("xs.sessionUpdate",sessionUpdate);
            attributes.put("xs.systemId", StartConfig.getParamValueFromKey(StartConfig.systemId));
            attributes.put("xs.systemReg", SystemInfoDTO.getConfig().getSystemExist());
            attributes.put("xs.sourceSystemId", BaggageUtil.getTraceVar(context, "xsAuthSystemId") == null ? StartConfig.getParamValueFromKey(StartConfig.systemId):BaggageUtil.getTraceVar(context, "xsAuthSystemId"));

            TraceContextVars.get()
                    .set("xs.userId",userRequest.getUserid() == null ? "" : userRequest.getUserid())
                    .set("endpoint-api",BaggageUtil.getTraceVar(context, "endpoint-api")==null?"":BaggageUtil.getTraceVar(context, "endpoint-api"))
                    .set("xs.sessionId",userRequest.getSessionId() == null ? "" : userRequest.getSessionId())
                    .set("xs.requestDate",userRequest.getRequestDate() == null ? "" : userRequest.getRequestDate().toString())
                    .set("xs.sessionUpdate",sessionUpdate.toString());
//            Baggage baggage2= Baggage.current();
//            System.out.println("###debug012 jedis current baggage " + baggage2.toString());
        } catch (Throwable e) {
            StartConfig.throwableStackPrinter(e);
        }
    }
}
